import { Cls, IVec2 } from "../util/Defined";
import { IPoolObj, Pool } from "../util/Pool";
import { ECSEntity } from "./ECSEntity";
import { ECSPoolCmp } from "./ECSPoolCmp";

/**
 * [ECS]实体组件
 */
export abstract class ECSCmp implements IPoolObj {
	/** 对象池,如果有的话 当组件需要被回收时会调用pool的回收 */
	get pool(): Pool<ECSCmp> {
		return null;
	}

	/** 组件附加的实体id */
	entityId: number;
	/** 组件附加的实体 */
	entity: ECSEntity;
	_enable: boolean;
	_added: boolean;

	/** 组件是否启用，当设为false时不会被sys处理 */
	get enable() {
		return this._enable;
	}

	set enable(b: boolean) {
		if (this._enable !== b) {
			const mgr = this.entity.cmpMgr;
			b ? mgr.enable(this) : mgr.disable(this);
		}
	}

	constructor(...args: any[]) {
		if (!this.pool) {
			this.onAlloc(...args);
		}
	}

	onAlloc(...args: any[]): void {
		this._enable = true;
		this._added = false;
		this.onInit(...args);
	}

	onFree(): void {
		this.onClear();
		this.entityId = null;
	}

	doAdd() {
		if (!this._added) {
			this._added = true;
			this.onAdd();
		}
	}

	/**
	 * (虚方法)
	 * 初始化组件
	 * @param args
	 */
	protected onInit(...args: any[]) {}

	/**
	 * (虚方法)
	 * 当真正添加到场景时触发
	 */
	protected onAdd() {}

	/**
	 * (虚方法)
	 * 清理组件
	 */
	protected onClear() {}

	/**
	 * 从实体中移除自身
	 */
	removeSelf() {
		this.removeCmp(this);
	}

	// ============ 封装实体的一些方法方便调用 ============

	/** 所在场景 */
	get scene() {
		return this.entity.scene;
	}

	/** 实体位置 */
	get pos() {
		return this.entity.pos;
	}

	/** 实体旋转值(弧度) */
	get rot() {
		return this.entity.rot;
	}

	set rot(v: number) {
		this.entity.rot = v;
	}

	get dir() {
		return this.entity.dir;
	}

	/** 缩放(请通过setScale设置) */
	get scale() {
		return this.entity.scale;
	}

	/** 设置朝向 */
	setDir(x: number, y: number) {
		return this.entity.setDir(x, y);
	}

	/** 设置朝向 */
	setDirTo(dir: Readonly<IVec2>) {
		return this.entity.setDirTo(dir);
	}

	/** 设置缩放 */
	setScale(x: number, y = x) {
		return this.entity.setScale(x, y);
	}

	/** 旋转变换矩阵 */
	get trans() {
		return this.entity.trans;
	}

	/**
	 * 是否存在对应组件
	 * @param cmpType 组件类型
	 */
	hasCmp(cmpType: Cls<ECSCmp>) {
		return this.entity.hasCmp(cmpType);
	}

	/**
	 * 获取对应组件类型的第一个组件
	 * @param cmpType 组件类型
	 * @param checkAdd 只获取已执行了onAdd的组件
	 */
	getCmp<T extends ECSCmp>(cmpType: Cls<T>, checkAdd = false): T {
		return this.entity.getCmp(cmpType, checkAdd);
	}

	/**
	 * 获取对应组件类型的所有组件
	 * @param cmpType 组件类型
	 * @param checkAdd 只获取已执行了onAdd的组件
	 */
	getCmps<T extends ECSCmp>(cmpType: Cls<T>, checkAdd = false): readonly T[] {
		return this.entity.getCmps(cmpType, checkAdd);
	}

	/**
	 * 获取对应组件类型的第一个组件 如果没有则添加
	 * @param cmpType 组件类型
	 * @param checkAdd 只获取已执行了onAdd的组件
	 */
	getOrAddCmp<T extends ECSCmp>(cmpType: Cls<T>, checkAdd = false): T {
		return this.entity.getOrAddCmp(cmpType, checkAdd);
	}

	/**
	 * 获取对应组件类型的第一个组件 如果没有则添加
	 * @param cmpPool 组件对象池
	 * @param checkAdd 只获取已执行了onAdd的组件
	 */
	getOrAddCmpByPool<T extends ECSCmp>(cmpPool: Pool<T>, checkAdd = false): T {
		return this.entity.getOrAddCmpByPool(cmpPool, checkAdd);
	}

	/**
	 * 添加组件
	 * @param cmpType 组件类型
	 */
	addCmp<T extends ECSCmp>(cmpType: Cls<T>): T {
		return this.entity.addCmp(cmpType);
	}

	/**
	 * 添加组件(通过对象池)
	 * @param cmpPool 组件对象池
	 */
	addCmpByPool<T extends ECSPoolCmp>(cmpPool: Pool<T>): T {
		return this.entity.addCmpByPool(cmpPool);
	}

	/**
	 * 添加组件(通过对象池带参数)
	 * @param cmpPool 组件对象池
	 * @param args 参数
	 */
	addCmpByPoolArgs<T extends ECSPoolCmp>(cmpPool: Pool<T>, ...args: any[]): T {
		return this.entity.addCmpByPoolArgs(cmpPool, ...args);
	}

	/**
	 * 移除组件
	 * @param cmp 组件
	 */
	removeCmp(cmp: ECSCmp) {
		return this.entity.removeCmp(cmp);
	}

	/**
	 * 移除组件类型
	 * @param cmpType 组件类型
	 */
	removeCmpType(cmpType: Cls<ECSCmp>) {
		return this.entity.removeCmpType(cmpType);
	}
}
